<?php

/**
 * WPIDS
 * Requirements: WordPress, PHP5, SimpleXML
 *
 * Copyright (c) 2008 BlogSecurity (http://blogsecurity.net)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the license.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * @package WPIDS
 */

if (eregi("^ids\-admin\.php", basename($_SERVER['PHP_SELF']))) {
    die('You cannot call this file directly.');
}
  
  $prefix = ereg_replace("[^-_[:alnum:]]", "", $GLOBALS['table_prefix']);
  $attackfields = array("GET", "POST", "REQUEST", "SERVER URI", "SERVER REF", "COOKIE");
  
if (isset($_POST['SaveSet'])) {
    check_admin_referer('wp-ids-savesettings');
    update_option("wpids-emailwhen", (ctype_digit($_POST['emailwhen'])? $_POST['emailwhen'] : '15'));
    update_option("wpids-emailto", (ereg("^[_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)*@([a-zA-Z0-9-]+\.)+([a-zA-Z]{2,4})$", $_POST['emailto'])? $_POST['emailto'] : ''));
    update_option("wpids-blockat", (ctype_digit($_POST['blockat'])? $_POST['blockat'] : '50'));
    update_option("wpids-banfor", (ctype_digit($_POST['banfor'])? $_POST['banfor'] : '10'));
    update_option("wpids-showlate", (ctype_digit($_POST['showlate']) ? $_POST['showlate'] :'25'));
    update_option("wpids-keeptable", (!empty($_POST['keeptable']))? '1' : '0');
    update_option("wpids-dolog", (!empty($_POST['dolog']))? '1' : '0');
    update_option("wpids-filter", (!empty($_POST['filter']))? 'json' : 'xml');
    update_option("wpids-ignore", (ctype_digit($_POST['ignore'])? $_POST['ignore'] : '15'));
    update_option("wpids-sanitize", (ctype_digit($_POST['sanitize'])? $_POST['ignore'] : '15'));
    update_option("wpld-lockpage", (!empty($_POST['lockpage']))? '1' : '0');
    update_option("wpld-framebrk", (!empty($_POST['framebrk']))? '1' : '0');
    update_option("wpld-blocktor", (!empty($_POST['blocktor']))? '1' : '0');
    update_option("wpld-admin-ip", ereg_replace("[^[:digit:].,]", "", $_POST['admin-ip']));
    update_option("wpld-xmlrpc", (!empty($_POST['xmlrpc'])? '1' : '0'));
}

/**
 * checks if newer filter are available and returns the 
 * value as well as state flag
 * 
 * //TODO: why do we return a status flag and not the staus itself?
 * 
 * @param msg
 * @return integer status flag
 */
function wpids_checkfilter(&$msg) {

    $filterend = (get_option("wpids-filter") == 'xml')? 'xml' : 'json';
    if (false === ($handle = @fopen("https://svn.php-ids.org/svn/trunk/lib/IDS/default_filter.".$filterend, "r"))) {
        $handle = @fopen("http://php-ids.org/default_filter.".$filterend, "r");
        $altfilter = true;
    }

    if ($handle !== false) {
        while (!feof($handle)) {
            $remote_filter .= fgets($handle, 4096);
        }
        fclose($handle);
        $handle = fopen(ABSPATH."wp-content/plugins/wp-ids/IDS/default_filter.".$filterend, "r");
        
        while (!feof($handle)) {
          $local_filter .= fgets($handle,4096);
        }
        fclose($handle);
        if ($local_filter<>$remote_filter) {
            $getfilter = (isset($altfilter))? 'http://php-ids.org/default_filter.'.
                $filterend:'https://svn.php-ids.org/svn/trunk/lib/IDS/default_filter.'.$filterend;

            $msg = 'New filter rules are available for the WPIDS: <a href="'.
                $getfilter.'">Filter Download</a>.<br /> We recommend that you update your filter 
                rules as soon as possible. That guarantees best protection level combined with 
                less false positives.';

            return 0;
        } else {
            $msg = 'WPIDS filter rules are up to date!';
            return 2;
        } 
    }else {
        $msg = 'Couldn\'t contact server for latest filter rules, Please try again later.';
        return 1;
    }
}

if (isset($_POST['stats']) && $_POST['stats'] == 'Search Stats') {
    if (function_exists("check_admin_referer")) {
        check_admin_referer('wp-ids-stats');
    }
?>
<div id="wpids_wrapper">
    <div class="content">
        <form method="post" id="idS">
        <?php
            if (function_exists("wp_nonce_field")) {
                wp_nonce_field("wp-ids-stats");
            }
        ?>
            <label>Show all Records where:</label>
            <select name="where">
                <option>Impact</option>
                <option>IP</option>
                <option>Page</option>
                <option>Status NOT used</option>
                <option>Tag</option>
                <option>Value</option>
            </select>
            <select name="operator">
                <option>is</option>
                <option>is not</option>
                <option>is Like</option>
            </select>
            <input type="text" name="searchvalue" />
            <label>Show not more than</label>
            <input type="text" name="limit" />
            <input type="submit" name="stats" value="Search Stats" />
        </form>
<?php
//Display code
      $idsquery = "SELECT t1.id AS `id_org`, `ip`, `value`, `page`, `tag`, `date`, `impact`, `type` FROM `".$prefix."sec_log` As t1 LEFT JOIN `".$prefix."sec_intrusions` AS t2 ON t1.ref_id = t2.id ";
      switch (strtolower($_POST['where'])) {
          case 'tag': $idsquery .= "WHERE `tag`";
              break;
          case 'value': $idsquery .= "WHERE `value`";
              break;
          case 'page': $idsquery .= "WHERE `page`";
              break;
          case 'impact': $idsquery .= "WHERE t2.impact";
              break;
          case 'ip': $idsquery .= "WHERE `ip`";
              break;
          default: $query_err = TRUE;
              break;
      }
      $searchfor = ereg_replace("(;|'|\"|%22|%27)", "", $_POST['searchvalue']);
      switch (strtolower($_POST['operator'])) {
          case 'is like': $idsquery .= " LIKE '%".$searchfor."%'";
              break;
          case 'is':  $idsquery .= "='".$searchfor."'";
              break;
          case 'is not': $idsquery .= "<>'".$searchfor."'";
              break;
          default: $query_err = TRUE;
              break;
      }
      if (isset($query_err) && $query_err === TRUE && $_POST['searchfor'] != "") {
          echo ("<strong>Can't run query, some Parameters where corrupt or Missing. Please retry!</strong>");
      } else {
          $idsquery .= " ORDER BY t1.id DESC ";
          (ctype_digit($_POST['limit']) && $_POST['limit'] !== 0)? $idsquery .= " LIMIT 0,".$_POST['limit'] : $idsquery .= " LIMIT 0, 25";
          $wpdb =& $GLOBALS['wpdb']; 
          $result = $wpdb->get_results($idsquery, ARRAY_A);
          echo "<table> <tr>
              <th>ID</th>
              <th>Value</th>
              <th>Tag</th>
              <th>Page</th>
              <th>IP</th>
              <th>Impact</th>
              <th>Time</th></tr>";
          if ($result !=NULL) {
              $rowNum = 0;
              foreach ($result as $row) {
                  $tag = (trim($row['tag']) != "")? ereg_replace("['\"<>]", "", $row[tag]): $attackedfields[$row['type']]; 
                  $row['impact'] = ($row['impact'] == NULL)? "-" : (int) $row['impact'];
                  echo "<tr class=\"bgcolour".(fmod($rowNum, 2) == 1? '1' : '2')."\"><td>".(int) $row[id_org]."</td><td>".
                      ereg_replace("['\"<>]", "", $row[value])."</td><td>".$tag."</td><td>".
                      substr(ereg_replace("['\"<>]", "", $row[page]), 0, 30)."...</td><td>".ereg_replace("['\"<>]", "", $row[ip]).
                      "</td><td>".$row[impact]."</td><td>".ereg_replace("['\"<>]", "", $row[date])."</td></tr>\n";
                      $rowNum++;
              }
          } else {
              echo ("</table>No entries found for your criteria!");
          }
        }
} else {
?>
    <div id="wpids_wrapper">
    <form method="post" id="idS">
    <?php
        if (function_exists("wp_nonce_field")) {
            wp_nonce_field("wp-ids-stats");
        }
    ?>
        <input type="submit" value="Search Stats" name="stats">
    </form>

    <h2>WPIDS <span>with PHPIDS v0.4.7</span></h2>
    <div class="content">
        <p>
            By <a href="http://www.thespanner.co.uk/">Gareth Heyes</a>, 
            <a href="http://phsoftware.de/">Philipp Heinze</a> &amp;
            <a href="http://php-ids.org/">Mario Heiderich</a>
        </p>
        <p>
            WPIDS utilizes the <a href="http://phpids.org" target="_blank">PHPIDS</a> for protecting your blog.
        </p>
        <p>
            This plugin checks all input parameters against a highly tested rule set against 
            attack patterns. If PHPIDS detects some suspicious input the request will be blocked and 
            logged to protect you and your blog from possible harm.
        </p>
        <p>
            Any bad request is given an impact - with height depending on the severity of the detected attack patterns. 
            This impact allows you to control how WPIDS works for you. Check out the settings below...    
        </p>
    </div>

    <?php
        if (!function_exists('phpversion') || phpversion() < '5.1.6') { ?>
        <h3 class="attention">Attention:</h3>
        <div class="content">
           <p>
               Your need at least PHP version 5.1.6 or greater (your version:
               
                <?php 
                    if (!function_exists('phpversion')) {
                        echo ('Version prior PHP4');
                    } else {
                        echo 'Version '.phpversion();
                    }
                ?>
                ), therefore it's not possible to use PHPIDS. WPIDS runs now only with a subset of features, 
                so many attacks may remian undetected. Please consider to upgrade to the latest PHP version  
                to benefit from all security features of that plugin.
            </p>
            <p>
                You can grab the latest copy from:<a href="http://www.php.net/downloads.php">PHP.net</a>
            </p>
        </div>
    <?php } ?>

    <h3
    <?php
        $state = array ("attention", "problem", "");
        echo ' class="'.$state[wpids_checkfilter($msgrt)].'"';
    ?>>Filter rules:
    </h3>

    <div class="content">
        <?php echo $msgrt; ?>
    </div>

    <form method="post" id="idS">
    <h3>Options</h3>

    <?php
        if (function_exists("wp_nonce_field")) {
            wp_nonce_field("wp-ids-savesettings");
        }
    ?>

    <fieldset>
        <legend>WPIDS:</legend>
        <p>
            <label>Send an Email to:</label>
             <input type="Text" name="emailto" value="<?php echo get_option("wpids-emailto");?>" size="20" maxlength="">

        </p>
        <p>
            <label>Maximum impact to ignore bad requests:</label>
            <input type="Text" name="ignore" value="<?php echo get_option("wpids-ignore");?>" size="3">
        </p>
        <p>
            <label>Minimum impact to sanitize bad requests:</label>
            <input type="Text" name="sanitze" value="<?php echo get_option("wpids-sanitize");?>" size="3">
        </p>
        <p>
            <label>Minimum impact to send an alert mail:</label>
            <input type="Text" name="emailwhen" value="<?php echo get_option('wpids-emailwhen');?>" size="3">
        </p>
        <p>
            <label>Minimum impact to block the request:</label>
            <input type="Text" name="blockat" value="<?php echo get_option("wpids-blockat");?>" size="3">
        </p>
        <p>
            <label>Show latest: </label>
            <input type="Text" name="showlate" value="<?php echo get_option("wpids-showlate");?>" size="3"> 
            <span> bad requests below</span>
        </p>
        <p>
            <label>Keep log entries if WPIDS gets disabled:</label>
            <input class="checkbox" type="Checkbox" name="keeptable" value="1" <?php echo (get_option("wpids-keeptable") == 1)? 'checked' : '';?>>
        </p>
        <p>
            <label>Log blocked intrusions to database:</label>
            <input class="checkbox" type="Checkbox" name="dolog" value="1" <?php echo (get_option("wpids-dolog") == 1)? 'checked' : '';?>>
        </p>
        <p>
            <label>Use JSON filter rules (may increase performance a little bit):</label>
            <input class="checkbox" type="Checkbox" name="filter" value="1" <?php echo (get_option("wpids-filter") == 'json')? 'checked' : '';?>>
        </p>
        <p>
            <input type="Submit" name="SaveSet" value="Save Settings" class="submit" />
        </p>
    </fieldset>
    <fieldset>
        <legend>WP Lockdown:</legend>
        <p>
        <label>Disable forgotten password features of Wordpress:</label>
        <input class="checkbox" type="Checkbox" name="lockpage" value="1" <?php echo (get_option("wpld-lockpage") == 1)? 'checked' : '';?>>
        </p>
        <p>
        <label>Enable Lockdown Framebreaker (Prevents evil sites from including your site on their domain):</label>
        <input class="checkbox" type="Checkbox" name="framebrk" value="1" <?php echo (get_option("wpld-framebrk") == 1)? 'checked' : '';?>>
        </p>
        <p>
        <label>Disable XML-RPC ability (if you don't use Offline Writers it's recommend to disable XML-RPC requests):</label>
        <input class="checkbox" type="Checkbox" name="xmlrpc" value="1" <?php echo (get_option("wpld-xmlrpc") == 1)? 'checked' : '';?>>
        </p>
        <!--p>
            <label>Disallow Access to your Blog from a Tor exit-node:</label>
            <input class="checkbox" type="Checkbox" name="blocktor" value="1" <?php echo (get_option("wpld-blocktor") == 1)? 'checked' : '';?>>
        </p-->
        <!-- p>
            <label>WP-Admin IP restriction (Separate multiple IPs with commas):<br />* Warning you must use a static IP address otherwise you may not be able to access your blog.</label>
            <textarea name="admin-ip" maxlength="100" id="adminIP"><?php echo get_option("wpld-admin-ip");?></textarea> <input type="button" value="Add my IP" class="submit" onclick="document.getElementById('adminIP').value = '<?php echo $_SERVER['REMOTE_ADDR']?>'" />
        </p-->
        <p>
            <input type="Submit" name="SaveSet" value="Save Settings" class="submit">
        </p>
    </fieldset>
    </form>
             <h3>Last Blocked Bad Requests:</h3>
             <table>
                <tr>
                    <th>ID</th>
                    <th>Value</th>
                    <th>Tag</th>
                    <th>Page</th>
                    <th>IP</th>
                    <th>Impact</th>
                    <th>Time</th>
                </tr>
                <?php
                    $wpdb =& $GLOBALS['wpdb'];//retrieving and showing the latest blocked Bad Requests
                    $records = $wpdb->get_results("SELECT t1.id AS id_org, `value`, `tag`, `ip`, `impact`, `date`, `page`, `type`  FROM `".$prefix."sec_log` AS t1 LEFT JOIN `"
                    .$prefix."sec_intrusions` AS t2 ON t1.ref_id = t2.id ORDER BY t1.id DESC LIMIT ".get_option("wpids-showlate"), ARRAY_A);
                    if ($records != NULL) {
                        $rowNum = 0;
                        foreach ($records as $row) {
                            $row['impact'] = ($row['impact'] == NULL)? "-" : (int) $row['impact'];
                            $tag = (trim($row['tag']) != "")? ereg_replace("['\"<>]", "", $row['tag']): $attackfields[$row['type']]; 
                            echo "<tr class=\"bgcolour".(fmod($rowNum, 2) == 1? '1' : '2')."\"><td>".(int) $row[id_org]."</td><td>".
                            ereg_replace("['\"<>]", "", $row[value])."</td><td>".$tag."</td><td>".
                            substr(ereg_replace("['\"<>]", "", $row[page]), 0, 30)."...</td><td>".ereg_replace("['\"<>]", "", $row[ip]).
                            "</td><td>".$row[impact]."</td><td>".ereg_replace("['\"<>]", "", $row[date])."</td></tr>\n";
                            $rowNum++;
                        }
                    } else {
                        echo ("<tr class=\"bgcolour1\"><td colspan=\"8\" style=\"text-align:center;\">No Intrusions where logged yet, congrats!</td></tr>");
                    }
                ?>
            </table>
        <h4>Legend:</h4>
        <div class="content">
        <strong>Name Values:</strong> <b>COOKIE</b> - Bad Value within $_COOKIE Array, <b>GET</b> - Bad Value within $_GET Array, <b>POST</b> - Bad Value within $_POST Array, <b>REQUEST</b> - Bad Value within $_REQUEST Array, <b>SERVER RURI</b> - Bad Value in $_SERVER[REQUEST_URI] <b>SERVER REF</b> - Bad Value in $_SERVER[HTTP_REFERER]
<?php 
}?>
    </div>
</div>
